package com.seeyon.apps.kkSample.manager.impl;

import com.seeyon.apps.collaboration.manager.ColManager;
import com.seeyon.apps.collaboration.po.ColSummary;
import com.seeyon.apps.kkSample.dao.KKESignDao;
import com.seeyon.apps.kkSample.enums.LogsFormEnum;
import com.seeyon.apps.kkSample.enums.UnComplyInfoEnum;
import com.seeyon.apps.kkSample.manager.KKEsignCallBackManager;
import com.seeyon.apps.kkSample.manager.KKEsignContractFileSignManager;
import com.seeyon.apps.kkSample.manager.KKEsignManager;
import com.seeyon.apps.kkSample.po.SHKKResult;

import com.seeyon.apps.kkSample.utils.UserSessionUtil;
import com.seeyon.apps.kkSample.utils.cap4.Cap4FormUtil;
import com.seeyon.apps.kkSample.utils.http.HttpRestUtil;
import com.seeyon.cap4.form.api.FormApi4Cap4;
import com.seeyon.cap4.form.bean.FormBean;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.cap4.form.bean.FormFieldBean;
import com.seeyon.cap4.form.bean.FormTableBean;
import com.seeyon.cap4.form.modules.engin.trigger.CAP4FormTriggerManager;
import com.seeyon.cap4.form.modules.event.FormDataAfterSubmitEvent;
import com.seeyon.cap4.form.modules.event.FormDataBeforeSubmitEvent;
import com.seeyon.cap4.form.service.CAP4FormManager;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.ModuleType;
import com.seeyon.ctp.common.constants.ApplicationCategoryEnum;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.common.filemanager.manager.AttachmentManager;
import com.seeyon.ctp.common.filemanager.manager.FileManager;
import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.common.po.filemanager.V3XFile;
import com.seeyon.ctp.event.EventDispatcher;
import com.seeyon.ctp.organization.bo.V3xOrgMember;
import com.seeyon.ctp.organization.manager.OrgManager;
import com.seeyon.ctp.util.*;
import com.seeyon.oainterface.exportData.commons.AttachmentExport;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.*;

public class KKEsignCallBackManagerImpl implements KKEsignCallBackManager {

    private static final Log LOG = CtpLogFactory.getLog(KKEsignCallBackManagerImpl.class);
    private String appUrl;
    private String appId;
    private String secret;
    private String upFile;
    private String unTmpCode;
    private String OAurl;
    private ColManager colManager = (ColManager) AppContext.getBean("colManager");
    private OrgManager orgManager = (OrgManager) AppContext.getBean("orgManager");
    private FileManager fileManager = (FileManager) AppContext.getBean("fileManager");
    private KKEsignManager kkEsignManager = (KKEsignManager) AppContext.getBean("kkEsignManager");
    private FormApi4Cap4 formApi4Cap4 = (FormApi4Cap4) AppContext.getBean("formApi4Cap4");
    private CAP4FormManager cap4FormManager = (CAP4FormManager) AppContext.getBean("cap4FormManager");
    private CAP4FormTriggerManager cap4FormTriggerManager = (CAP4FormTriggerManager) AppContext.getBean("cap4FormTriggerManager");
    private KKESignDao kkESignDao = (KKESignDao) AppContext.getBean("kkESignDao");
    private AttachmentManager attachmentManager = (AttachmentManager) AppContext.getBean("attachmentManager");
    private KKEsignContractFileSignManager kkESignContractFileSignManager = (KKEsignContractFileSignManager) AppContext.getBean("kkESignContractFileSignManager");

    /**
     * 解析回调事件类型
     *
     * @param bodyMap
     */
    @Override
    public void action(Map<String, Object> bodyMap) {
        //请求体不为空
        if (!bodyMap.isEmpty()) {
            //获取应用配置信息
            HashMap<String, Object> unComplyInfo = (HashMap<String, Object>) kkEsignManager.getUnComplyInfo();
            this.appUrl = unComplyInfo.get(UnComplyInfoEnum.appUrl.getFiledName()).toString();
            this.appId = unComplyInfo.get(UnComplyInfoEnum.appID.getFiledName()).toString();
            this.secret = unComplyInfo.get(UnComplyInfoEnum.secret.getFiledName()).toString();
            this.upFile = unComplyInfo.get(UnComplyInfoEnum.upFile.getFiledName()).toString();
            this.unTmpCode = unComplyInfo.get(UnComplyInfoEnum.unTmpCode.getFiledName()).toString();
            this.OAurl = unComplyInfo.get(UnComplyInfoEnum.OAurl.getFiledName()).toString();
            //获取token
            String token = kkEsignManager.getToken(this.appUrl, this.appId, this.secret);
            //请求头参数
            HashMap<String, Object> headerParams = new HashMap<>();
            headerParams.put(UnComplyInfoEnum.appID.getFiledName(), appId);
            headerParams.put(UnComplyInfoEnum.token.getFiledName(), token);
            headerParams.put(UnComplyInfoEnum.contentType.getFiledName(), UnComplyInfoEnum.contentType.getFiledShowValue());
            //事件类型
            String action = bodyMap.get("action").toString();
            LOG.info("解析回调事件 - 事件类型：" + action);
            Map<String, Object> logMap = new HashMap();
            //签署流程id
            String signFlowId = bodyMap.get("signFlowId").toString();
            //更新时间
            logMap.put(LogsFormEnum.updateTime.getFiledShowValue(), DateUtil.currentDate());
            //状态
            logMap.put(LogsFormEnum.status.getFiledShowValue(), bodyMap.get("resultDescription"));
            if ("SIGN_MISSON_COMPLETE".equals(action)) {
                //签署人签署完成通知
                //更新流程表：回写附件
                LOG.info("解析回调事件 - 更新流程表");
                updateFlowForm(this.appUrl, headerParams, signFlowId, this.unTmpCode);
            } else if ("SIGN_FLOW_COMPLETE".equals(action)) {
                //流程结束通知
            } else if ("OPERATOR_READ".equals(action)) {
                //签署人已读
            } else if ("TRANSMISS_SIGN".equals(action)) {
                //经办人转交签署任务通知
            } else if ("FILE_UNAVAILABLE".equals(action)) {
                //文件已加密/已损坏通知
            } else {
                //其他通知
            }
            //更新签署日志底表
            updateUnFlowForm(signFlowId, logMap, this.unTmpCode);
        }
    }

    /**
     * 更新流程表：回写附件
     *
     * @param appUrl
     * @param headerParams
     * @param signFlowId
     * @param tmpCode
     */
    @Override
    public void updateFlowForm(String appUrl, Map<String, Object> headerParams, String signFlowId, String tmpCode) {
        String summaryId = getSummaryId(tmpCode, signFlowId);//通过查询日志底表数据获得流程表的流程id
        //下载已签署文件及附属材料
        LOG.info("下载已签署文件及附属材料：" +summaryId);
        SHKKResult result = kkESignContractFileSignManager.fileDownLoadUrl(appUrl, headerParams, signFlowId);
        LOG.info("下载已签署文件及附属材料：" + result.toString());
        if (result.getCode() == 0) {
            Map<String, Object> data = result.getData();
            ArrayList<Map> fileList = (ArrayList<Map>) data.get("files");
            List<AttachmentExport> attachmentExportList = new ArrayList<AttachmentExport>();
            //遍历已签署文件的下载地址，并下载保存到 OA 系统
            for (int i = 0; i < fileList.size(); ++i) {
                HashMap<String, Object> file = (HashMap<String, Object>) fileList.get(i);
                String fileId = (String) file.get("fileId");//签署文件ID
                String fileName = (String) file.get("fileName");//签署文件名称
                String downloadUrl = (String) file.get("downloadUrl");//已签署文件下载链接（有效期60分钟）
                LOG.info("流程表单签署文件：[summaryId:" + summaryId + "] " + "[fileId:" + fileId + "] " + "[downloadUrl:" + downloadUrl + "]");

                //下载，获取文件流
                InputStream inputStream = HttpRestUtil.doConForFile(downloadUrl);
                //保存文件
                V3XFile v3XFile = null;
                try {
                    v3XFile = fileManager.save(inputStream, ApplicationCategoryEnum.cap4Form, fileName, new Date(), true);
                    String sysFileId = v3XFile.getId().toString();
                    if (StringUtils.isNotBlank(sysFileId)) {
                        AttachmentExport attachmentExport = new AttachmentExport();
                        attachmentExport.setId(Long.parseLong(sysFileId));
                        attachmentExportList.add(attachmentExport);
                    }
                } catch (BusinessException e) {
                    LOG.error("签署文件保存本地失败" + e.getMessage(), e);
                } finally {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        LOG.error("inputStream.close();异常：" + e.getMessage(), e);
                    }
                }
            }

            //关联流程附件
            try {
                ColSummary colSummary = colManager.getSummaryById(Long.parseLong(summaryId));
                FormBean formBean = formApi4Cap4.getForm(colSummary.getFormAppid());
                Long recordId = colSummary.getFormRecordid();
                FormDataMasterBean formDataMasterBean = formApi4Cap4.getSessioMasterDataBean(recordId);
                if (formDataMasterBean == null) {
                    formDataMasterBean = formApi4Cap4.findDataById(recordId, formBean, null);
                }
                Long subRenferenceMore = (Long) Cap4FormUtil.getFieldValue(UnComplyInfoEnum.downFile.getFiledShowValue(), formDataMasterBean);
                if (subRenferenceMore == null) {
                    subRenferenceMore = UUIDLong.longUUID();
                }
                //关联附件
                relationAttachmentsFlow(Long.valueOf(summaryId), null, null, attachmentExportList, subRenferenceMore);
                //表单添加附件
                HashMap<String, Object> unComplyInfo = (HashMap<String, Object>) kkEsignManager.getUnComplyInfo();
                String downFile = unComplyInfo.get(UnComplyInfoEnum.downFile.getFiledName()).toString();
                formDataMasterBean.addFieldValue(Cap4FormUtil.getFieldName(downFile, formBean), subRenferenceMore);
                //保存并更新
                cap4FormManager.saveOrUpdateFormData(formDataMasterBean, formBean.getId(), true);
            } catch (Exception e) {
                LOG.error("获取表单数据对象异常：" + e.getMessage(), e);
            }
        }
    }

    /**
     * 关联流程附件
     *
     * @param summaryId            流程id
     * @param fileId               文件id -- 单控件单文件
     * @param subRenference        随机数(subRenference) -- 单控件单文件
     * @param attachmentExportList 附件集合 -- 单控件多文件
     * @param subRenferenceMore    随机数(subRenference) -- 单控件多文件
     *                             subRenference：ctp_file表中的ID，ctp_attachment表中的SUB_REFERENCE
     */
    @Override
    public void relationAttachmentsFlow(Long summaryId, String fileId, Long subRenference, List<AttachmentExport> attachmentExportList, Long subRenferenceMore) {
        Map<Long, Long[]> attMap = new HashMap<Long, Long[]>();
        if (StringUtils.isNotBlank(fileId)) { //单文件
            Long[] atteIds = new Long[]{Long.valueOf(fileId)};
            attMap.put(subRenference, atteIds);
        } else if (attachmentExportList != null && !attachmentExportList.isEmpty()) { //多文件
            Long[] atteIds = new Long[attachmentExportList.size() + 1];
            for (int i = 0; i < attachmentExportList.size(); i++) {
                Long atteId = attachmentExportList.get(i).getId();
                if (atteId != null) {
                    atteIds[i] = atteId;
                }
            }
            attMap.put(subRenferenceMore, atteIds);
        }
        //关联流程附件
//        if(MapUtils.isNotEmpty(attMap)) {
        if (!(attMap.isEmpty())) {
            for (Long subRe : attMap.keySet()) {
                attachmentManager.create(attMap.get(subRe), ApplicationCategoryEnum.cap4Form, summaryId, subRe);
            }
        }
    }

    /**
     * 通过签署流程Id查询日志表中的， 表单流程id
     *
     * @param tmpCode    日志底表编号
     * @param signFlowId 签署流程id
     * @return
     */
    @Override
    public String getSummaryId(String tmpCode, String signFlowId) {
        try {
            FormBean formBean = formApi4Cap4.getFormByFormCode(tmpCode);
            String logsFormName = formBean.getMasterTableBean().getTableName();
            FormTableBean masterTableBean = formBean.getMasterTableBean();
            String thirdIdField = Cap4FormUtil.getFieldName(LogsFormEnum.thirdId.getFiledShowValue(), formBean.getMasterTableBean());//日志表中第三方主键id（签署流程id）在数据库中的字段名：filed00**
            String flowIdField = Cap4FormUtil.getFieldName(LogsFormEnum.flowId.getFiledShowValue(), formBean.getMasterTableBean());//流程id在数据库中的字段名
            String flowId = kkESignDao.getLogsByThirdId(logsFormName, flowIdField, thirdIdField, signFlowId);
            return flowId;
        } catch (BusinessException e) {
            LOG.error("获取表单对象异常：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 更新e签宝签章日志底表
     *
     * @param signFlowId 签署流程id
     * @param logMap     需要更改的日志表数据
     * @param tmpCode    模板编号
     */
    @Override
    public void updateUnFlowForm(String signFlowId, Map<String, Object> logMap, String tmpCode) {
        try {
            FormBean formBean = formApi4Cap4.getFormByFormCode(tmpCode);
            if (formBean != null) {
                FlipInfo flipInfo = new FlipInfo(1, 20);
                Map<String, Object> where = new HashMap<String, Object>();
                if (StringUtils.isNotBlank(signFlowId)) {
                    where.put(formBean.getFieldBeanByDisplay(LogsFormEnum.thirdId.getFiledShowValue()).getName(), signFlowId);
                    List<FormDataMasterBean> formDataMasterBeanList = formApi4Cap4.findMasterDataList(flipInfo, formBean.getId(), null, where);
                    //如果查询到日志底表数据
                    if (CollectionUtils.isNotEmpty(formDataMasterBeanList)) {
                        FormDataMasterBean formDataMasterBean = formDataMasterBeanList.get(0);
                        V3xOrgMember v3xOrgMember = orgManager.getMemberById(formBean.getCreatorId());
                        String loginName = v3xOrgMember.getLoginName();
                        updateFormData(tmpCode, loginName, formDataMasterBean, logMap);
                    }
                }
            }
        } catch (BusinessException e) {
            LOG.error("通过模板编号获取表单对象异常：" + e.getMessage(), e);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新表单数据
     *
     * @param formCode
     * @param createLoginName
     * @param dataBean
     * @param param
     * @return
     * @throws BusinessException
     * @throws SQLException
     */
    public String updateFormData(String formCode, String createLoginName, FormDataMasterBean dataBean, Map<String, Object> param) throws BusinessException, SQLException {
        FormDataMasterBean oldFormDataMasterBean = dataBean;
        String ret = null;
        boolean needUpdate = false;
        Set<String> it = param.keySet();
        FormBean bean = formApi4Cap4.getFormByFormCode(formCode);
        for (String key : it) {
            FormFieldBean field = bean.getFieldBeanByDisplay(key);
            if ("VARCHAR".equals(field.getFieldType())) {
                String paramKey = ParamUtil.getString(param, key);
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (paramKey != null && field != null && !paramKey.equals(dataBean.getFieldValue(field.getName()))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else if ("DECIMAL".equals(field.getFieldType())) {
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getLong(param, key));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (!longToBigDecimal(ParamUtil.getString(param, key, "0")).equals(dataBean.getFieldValue(field.getName()))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else if ("TIMESTAMP".equals(field.getFieldType())) {
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (!dataBean.getFieldValue(field.getName()).equals(ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else if ("DATETIME".equals(field.getFieldType())) {
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (!dataBean.getFieldValue(field.getName()).equals(ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getDate(param, key, null, "yyyy-MM-dd HH:mm:ss", false));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else if ("TEXTAREA".equals(field.getFieldType())) {
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (!dataBean.getFieldValue(field.getName()).equals(ParamUtil.getString(param, key))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else if ("LONGTEXT".equals(field.getFieldType())) {
                if (null == dataBean.getFieldValue(field.getName())) {
                    if (Strings.isNotEmpty(ParamUtil.getString(param, key))) {
                        needUpdate = true;
                        dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                        if (Strings.isBlank(ret)) {
                            ret = "修改了表单的" + key;
                        } else {
                            ret += "," + key;
                        }
                    }
                } else if (!dataBean.getFieldValue(field.getName()).equals(ParamUtil.getString(param, key))) {
                    needUpdate = true;
                    dataBean.addFieldValue(field.getName(), ParamUtil.getString(param, key));
                    if (Strings.isBlank(ret)) {
                        ret = "修改了表单的" + key;
                    } else {
                        ret += "," + key;
                    }
                }
            } else {
                LOG.info("##上海区客开: 未配置类型: " + field.getFieldType() + " ,不能进行修改日志记录.");
            }
        }
        if (needUpdate) {
            ret += " 属性.";
            dataBean.setModifyDate(DateUtil.currentDate());
            boolean hasUser = false;
            if (AppContext.getCurrentUser() == null) {
                UserSessionUtil.newUserSession(createLoginName);
                hasUser = true;
            }

            FormDataBeforeSubmitEvent formDataBeforeSubmitEvent = new FormDataBeforeSubmitEvent(dataBean);
            // 触发表单数据入库前的事件
            EventDispatcher.fireEvent(formDataBeforeSubmitEvent);

            formApi4Cap4.saveOrUpdateFormData(dataBean, bean.getId(), true);

            FormDataAfterSubmitEvent formDataAfterSubmitEvent = new FormDataAfterSubmitEvent(dataBean);
            // 触发表单数据入库后的事件
            EventDispatcher.fireEvent(formDataAfterSubmitEvent);

            cap4FormTriggerManager.doTrigger(ModuleType.cap4UnflowForm.getKey(), dataBean.getId(), bean.getId(), null, null, "dataSave");
            if (hasUser) {
                UserSessionUtil.clearUserSession();
            }
        }
        return ret;
    }

    private BigDecimal longToBigDecimal(String val) {
        if (Strings.isEmpty(val)) {
            return new BigDecimal("0");
        } else {
            return new BigDecimal(val);
        }
    }
}
